package consumer

import (
	"encoding/json"
	"errors"
	"fmt"
	"new_for_deepseek_rabbitmq/config"
	"new_for_deepseek_rabbitmq/logger"
	"new_for_deepseek_rabbitmq/model"
	rabbitmqProject "new_for_deepseek_rabbitmq/project/rabbitmq"
	tencentlke "new_for_deepseek_rabbitmq/project/tencent/lke"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/streadway/amqp"
	"github.com/tealeg/xlsx/v3"
	"gorm.io/gorm"

	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	tencenterrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
	lke "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/lke/v20231130"
)

func QuestionAnswer() *questionAnswerStruct {
	return &questionAnswerStruct{}
}

const (
	TypeClassify = "classify"
	TypeBusiness = "business"
)

const (
	StatusPending = 0 // 待执行
	StatusRunning = 1 // 执行中
	StatusDone    = 2 // 执行完成
)

type questionAnswerStruct struct {
	Id                 int    //id
	Question           string //问题
	Answer             string //答案
	QrBizId            string //问答id
	TypeClassifyId     int    //类型分类id
	BusinessClassifyId int    //业务分类id
}

type classifyFindStruct struct {
	Title      string
	ParentId   int
	ParentPath string
	FindType   string
}

// 入口方法
func (q *questionAnswerStruct) Start() (err error) {

	ch, err := rabbitmqProject.GetChannel()
	if err != nil {
		logger.Error("获取RabbitMQ通道失败: %s", err.Error())
		return
	}
	defer rabbitmqProject.ReleaseChannel(ch)

	// 使用工具函数声明交换机和队列
	if err = rabbitmqProject.DeclareExchangeAndQueue(ch, rabbitmqProject.QuestionAnswerConfig); err != nil {
		logger.Error("初始化RabbitMQ失败: %s", err.Error())
		return
	}

	// 消费消息
	msgs, err := ch.Consume(
		rabbitmqProject.QuestionAnswerConfig.QueueName,
		"",
		false,
		false,
		false,
		false,
		nil,
	)
	if err != nil {
		logger.Error("设置消费者失败: %s", err.Error())
		return
	}

	// 循环消费消息
	for msg := range msgs {
		// 处理消息
		if err := q.processQuestionAnswer(msg); err != nil {
			logger.Error("处理消息失败: %s", err.Error())
			msg.Ack(false)
			continue
		}
	}

	return nil
}

func (q *questionAnswerStruct) processQuestionAnswer(msg amqp.Delivery) (err error) {
	var questionAnswerMessage rabbitmqProject.QuestionAnswerMessage
	if err := json.Unmarshal(msg.Body, &questionAnswerMessage); err != nil {
		logger.Error("解析问答消息失败: %s", err.Error())
		return err
	}

	db := model.GetInstance().DB

	//更新为执行中
	db.Model(&model.FilesModel{}).
		Where("id = ?", questionAnswerMessage.FileId).
		Update("status", StatusRunning)

	//打开excel文件
	xlFile, err := xlsx.OpenFile(questionAnswerMessage.FilePath)
	if err != nil {
		logger.Error("Failed to open file: %s", err.Error())
		return err
	}

	//获取第一个sheet
	sheet := xlFile.Sheets[0]

	var errBuilder strings.Builder

	//遍历sheet
	//从第二行开始遍历
	for i := 1; i < sheet.MaxRow; i++ {
		row, err := sheet.Row(i)
		if err != nil {
			logger.Error("Failed to get row: %s", err.Error())
			continue
		}

		//类型分类
		typeClassifyTitle := row.GetCell(0).Value
		//业务分类一级
		businessFirstTitle := row.GetCell(1).Value
		//业务分类二级
		businessSecondTitle := row.GetCell(2).Value
		//问题
		question := row.GetCell(3).Value
		//答案
		answer := row.GetCell(4).Value

		if question == "" || answer == "" {
			continue
		}

		//实例化问答类
		var questionAnswer questionAnswerStruct

		var classifyFind classifyFindStruct

		//类型分类
		if typeClassifyTitle != "" {
			//获取当前分类
			classifyFind.Title = typeClassifyTitle
			classifyFind.ParentId = 0
			classifyFind.FindType = TypeClassify
			questionAnswer.TypeClassifyId, err = classifyFind.classifyFindHandle()
			if err != nil {
				errBuilder.WriteString(fmt.Sprintf("第%d行，类型分类错误：%s\n", i, err.Error()))
				continue
			}
		}

		//业务分类
		if businessFirstTitle != "" {
			//业务分类一级
			classifyFind.Title = businessFirstTitle
			classifyFind.ParentId = 0
			classifyFind.FindType = TypeBusiness
			questionAnswer.BusinessClassifyId, err = classifyFind.classifyFindHandle()
			if err != nil {
				errBuilder.WriteString(fmt.Sprintf("第%d行，业务分类一级错误：%s\n", i, err.Error()))
				continue
			}

			//业务分类二级
			if businessSecondTitle != "" {
				classifyFind.Title = businessSecondTitle
				classifyFind.ParentId = questionAnswer.BusinessClassifyId
				classifyFind.FindType = TypeBusiness
				questionAnswer.BusinessClassifyId, err = classifyFind.classifyFindHandle()
				if err != nil {
					errBuilder.WriteString(fmt.Sprintf("第%d行，业务分类二级错误：%s\n", i, err.Error()))
					continue
				}
			}
		}

		//问答处理
		questionAnswer.Question = question
		questionAnswer.Answer = answer
		if err := questionAnswer.questionAnswerHandle(); err != nil {
			errBuilder.WriteString(fmt.Sprintf("第%d行，问答处理错误：%s\n", i, err.Error()))
			continue
		}
	}

	updateFile := map[string]interface{}{
		"status": StatusDone,
	}
	if errBuilder.Len() > 0 {
		errFileName := strings.Replace(questionAnswerMessage.FilePath, "uploads/", "", 1) + ".error.txt"
		os.WriteFile(errFileName, []byte(errBuilder.String()), 0644)
		updateFile["err_file"] = errFileName
	}

	//更新文件处理状态
	if err := db.Model(&model.FilesModel{}).Where("id = ?", questionAnswerMessage.FileId).Updates(updateFile).Error; err != nil {
		logger.Error("update file error: %s", err.Error())
		return err
	}

	//更新为执行完成
	msg.Ack(false)

	return nil
}

// 类型查询
func (t *classifyFindStruct) classifyFindHandle() (classifyId int, err error) {
	db := model.GetInstance().DB

	parentPath := ""
	//父级分类
	if t.ParentId != 0 {
		var parentClassify model.ClassifyModel
		if err = db.Where("id = ?", t.ParentId).First(&parentClassify).Error; err != nil {
			logger.Error("find parent type error: %s, parent id : %d", err, t.ParentId)
			err = errors.New("find parent type error")
			return
		}
		parentPath = parentClassify.ParentPath + "," + strconv.Itoa(t.ParentId)
	}

	//类型
	var classifyModel model.ClassifyModel
	db.Where("title = ?", t.Title).
		Where("parent_id = ?", t.ParentId).
		Where("type = ?", t.FindType).
		First(&classifyModel)
	if classifyModel.Id == 0 {
		var classifyCreate model.ClassifyModel
		classifyCreate.Title = t.Title
		classifyCreate.ParentId = t.ParentId
		classifyCreate.Type = t.FindType
		classifyCreate.ParentPath = parentPath
		db.Create(&classifyCreate)

		return classifyCreate.Id, nil
	}

	return classifyModel.Id, nil
}

// 问答判断
func (q *questionAnswerStruct) questionAnswerHandle() (err error) {

	var questionAnswerModel model.QuestionAnswerModel
	db := model.GetInstance().DB
	if err = db.Where("question = ?", q.Question).First(&questionAnswerModel).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			//创建文档
			return q.questionAnswerCreate()
		} else {
			logger.Error("find question answer error: %s", err)
			return
		}
	} else {
		//更新文档
		q.QrBizId = questionAnswerModel.QrBizId
		q.Id = questionAnswerModel.Id
		return q.questionAnswerUpdate()
	}
}

// 创建问答
func (q *questionAnswerStruct) questionAnswerCreate() (err error) {
	//创建文档
	request := lke.NewCreateQARequest()
	request.BotBizId = common.StringPtr(config.DefaultConfig.Tencent.Lke.BotBizId)
	request.Question = common.StringPtr(q.Question)
	request.Answer = common.StringPtr(q.Answer)
	request.AttrRange = common.Uint64Ptr(1)

	// 返回的resp是一个CreateQAResponse的实例，与请求对象对应
	response, err := tencentlke.LkeClient.CreateQA(request)
	if _, ok := err.(*tencenterrors.TencentCloudSDKError); ok {
		logger.Error("An API error has returned: %s", err.Error())
		return
	}
	if err != nil {
		logger.Error("create question answer api error: %s", err.Error())
		return
	}

	db := model.GetInstance().DB
	if err = db.Model(&model.QuestionAnswerModel{}).
		Create(map[string]interface{}{
			"qr_biz_id":            *response.Response.QaBizId,
			"type_classify_id":     q.TypeClassifyId,
			"business_classify_id": q.BusinessClassifyId,
			"question":             q.Question,
			"answer":               q.Answer,
			"created_at":           time.Now(),
			"updated_at":           time.Now(),
		}).Error; err != nil {
		logger.Error("create question answer db error: %s", err)
		return
	}

	return
}

// 更新问答
func (q *questionAnswerStruct) questionAnswerUpdate() (err error) {
	// 实例化一个请求对象,每个接口都会对应一个request对象
	request := lke.NewModifyQARequest()

	request.BotBizId = common.StringPtr(config.DefaultConfig.Tencent.Lke.BotBizId)
	request.QaBizId = common.StringPtr(q.QrBizId)
	request.Question = common.StringPtr(q.Question)
	request.Answer = common.StringPtr(q.Answer)

	// 返回的resp是一个ModifyQAResponse的实例，与请求对象对应
	_, err = tencentlke.LkeClient.ModifyQA(request)
	if _, ok := err.(*tencenterrors.TencentCloudSDKError); ok {
		logger.Error("An API error has returned: %s", err.Error())
		return
	}
	if err != nil {
		logger.Error("update question answer api error: %s", err.Error())
		return
	}

	db := model.GetInstance().DB
	if err = db.Model(&model.QuestionAnswerModel{}).
		Where("id = ?", q.Id).
		Updates(map[string]interface{}{
			"type_classify_id":     q.TypeClassifyId,
			"business_classify_id": q.BusinessClassifyId,
			"question":             q.Question,
			"answer":               q.Answer,
			"updated_at":           time.Now(),
		}).Error; err != nil {
		logger.Error("update question answer db error: %s", err)
		return
	}

	return
}
